//! Type declaration parser

use super::super::{parse_type, Parser};
use super::struct_decl::{parse_generic_params, parse_go_style_struct};
use crate::ast::decl::*;
use crate::ast::types::*;
use crate::error::{CompilerError, Result};
use crate::lexer::token::Token;

/// Parse type declaration (Go-style: type StructName struct { ... })
/// Returns either a TypeDecl or a StructDecl depending on the syntax
pub fn parse_type_declaration(parser: &mut Parser) -> Result<TypeDecl> {
    parser.expect(&Token::Type)?;

    if let Some(Token::Identifier(name)) = parser.peek().map(|t| &t.token) {
        let type_name = name.clone();
        parser.advance()?;

        let generics = parse_generic_params(parser)?;

        // Check if this is a Go-style struct declaration: type StructName struct { ... }
        if parser.consume(&Token::Struct)? {
            // Parse Go-style struct
            let struct_decl = parse_go_style_struct(parser, type_name.clone(), generics)?;

            // For Go-style structs, we need to return a StructDecl instead of TypeDecl
            // This is a special case where the parser needs to return a different type
            // We'll handle this in the parser by checking the return type
            return Ok(TypeDecl {
                name: struct_decl.name.clone(),
                type_def: Type::Struct(StructType {
                    name: struct_decl.name.clone(),
                    type_args: vec![],
                    location: struct_decl.location,
                }),
                location: struct_decl.location,
            });
        } else {
            // Original type alias syntax: type Name = Type
            parser.expect(&Token::Assign)?;

            let type_def = parse_type(parser)?;
            if type_def.is_none() {
                return Err(CompilerError::syntax(
                    parser.current_location().line,
                    parser.current_location().column,
                    "Expected type definition after '='",
                ));
            }

            parser.expect(&Token::Semicolon)?;

            Ok(TypeDecl {
                name: type_name,
                type_def: type_def.unwrap(),
                location: parser.current_location(),
            })
        }
    } else {
        Err(CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected type name after 'type'",
        ))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::parser::Parser;

    fn parse_type_decl(input: &str) -> Result<TypeDecl> {
        let mut parser = Parser::new(input.to_string(), None);
        parser.advance()?;
        parse_type_declaration(&mut parser)
    }

    #[test]
    fn test_parse_type_alias() {
        let result = parse_type_decl("type ID = int;");
        assert!(result.is_ok());
        let decl = result.unwrap();
        assert_eq!(decl.name, "ID");
        assert!(matches!(decl.type_def, Type::Basic(_)));
    }

    #[test]
    fn test_parse_type_alias_string() {
        let result = parse_type_decl("type Name = string;");
        assert!(result.is_ok());
        let decl = result.unwrap();
        assert_eq!(decl.name, "Name");
    }

    #[test]
    fn test_parse_type_alias_no_name_error() {
        let result = parse_type_decl("type = int;");
        assert!(result.is_err());
    }

    #[test]
    fn test_parse_type_alias_no_assign_error() {
        let result = parse_type_decl("type ID int;");
        // This should fail because we expect '=' after type name
        assert!(result.is_err());
    }
}
